//--------------------------------------------------------------
//
// Qizhi Zhang 
// ezhung@gmail.com
// http://www.moorwind.com
//
//--------------------------------------------------------------
package reader.model
{
	import __AS3__.vec.Vector;
	
	import flash.utils.Dictionary;
	import flash.utils.setTimeout;
	
	import reader.ApplicationFacade;
	import reader.core.ReaderModelLocator;
	import reader.dao.IBlogDAO;
	import reader.dao.IBlogSourceDAO;
	import reader.dao.ILabelDAO;
	import reader.events.FeedLoaderEvent;
	import reader.model.vo.BlogFetchVO;
	import reader.model.vo.BlogItemVO;
	import reader.model.vo.BlogLabelVO;
	import reader.model.vo.BlogSourceVO;
	import reader.model.vo.CountVO;
	import reader.model.vo.UserVO;
	import reader.utils.FeedLoader;
	import reader.utils.FeedLoaderList;
	import reader.utils.StringUtils;

	public class DataProxy extends BaseDataProxy implements IDataProxy
	{
		////////////////////////////////////////////////////////////////////////////////
		//public properties
		
		public static const NAME:String = "DataProxy";
		
		////////////////////////////////////////////////////////////////////////////////
		//private variables
		
		private var labelDAO:ILabelDAO;
		private var blogSourceDAO:IBlogSourceDAO;
		private var blogDAO:IBlogDAO;
		
		private var quickAddSubscribe:BlogSourceVO;
		private var addLabelBlogSource:BlogSourceVO;
		
		private var autoFeedLoader:FeedLoaderList;
		
		private var readerModelLocator:ReaderModelLocator = ReaderModelLocator.instance;
		
		//////////////////////////////////////////////////////////////////////////////
		//constructor
		public function DataProxy()
		{
			super(NAME);
			
			labelDAO = readerModelLocator.sqliteDAOFactory.labelDAO;
			blogSourceDAO = readerModelLocator.sqliteDAOFactory.blogSourceDAO;
			blogDAO = readerModelLocator.sqliteDAOFactory.blogDAO;
			
			autoFeedLoader = new FeedLoaderList(null);
			autoFeedLoader.addEventListener(FeedLoaderEvent.FEED_LIST, onFeedLoadListComplete_handler);
			autoFeedLoader.addEventListener(FeedLoaderEvent.LIST_COMPLETE, onFeedLoadListComplete_handler);
		}
		
		////////////////////////////////////////////////////////////////////////////////
		//methods
		
		/**  
		 * fetch blog labels and blogsource for creating labeltree xml.
		*/
		public function getLabels():void
		{
			readerModelLocator.blogLabels = labelDAO.selectAllLabels(readerModelLocator.user);
			readerModelLocator.blogSource = blogSourceDAO.selectAllBlogSource(readerModelLocator.user);
			
			if(autoFeedLoader.blogSource != readerModelLocator.blogSource)
			{
				autoFeedLoader.blogSource = readerModelLocator.blogSource;
			}
			sendNotification(ApplicationFacade.LABEL_TREE_CREATE, creatLabelTree());
		}
		
		/**  
		 * start auto update blog item from given subscribe.
		*/
		public function startAutoUpdateBlogItem():void
		{
			if(!autoFeedLoader.isUpdating)
				autoFeedLoader.start();
			else
			{
				setTimeout(autoFeedLoader.start, 5000);
			}	
		}
		/**  
		 * stop auto update blog item from given subscribe.
		*/
		public function stopAutoUpdateBlogItem():void
		{
			autoFeedLoader.stop();
		}
				
		/**  
		 * creat a new label.
		*/
		public function addLabel(label:BlogLabelVO, blogSource:BlogSourceVO = null):void
		{
			var labelid:int = labelDAO.insertLabel(label, readerModelLocator.user);
			blogSource.labelId = labelid;
			
			if(blogSourceDAO.updateBlogSource(blogSource))
			{
				getLabels();
			}
			
		}
		
		/**  
		 * remove the given label.
		*/
		public function removeLabel(label:BlogLabelVO):void
		{
			if(labelDAO.deleteLabel(label))
			{
				blogSourceDAO.resetBlogSourceLabel(label.labelid);
				getLabels();
			}
		}
		
		/**  
		 * remove the given labels.
		*/
		public function removeLabels(labels:Vector.<BlogLabelVO>):void
		{
			labelDAO.deleteLabels(labels);
			blogSourceDAO.resetBlogSourceLabels(labels);
			getLabels();
		}
		
		/**  
		 * fetch latest blogs for creating blogsummary box.
		*/
		public function getBlogSummary():void
		{
			var summary:Dictionary = blogDAO.selectSummary(BlogSourceVO.getNewBlogsBlogSource(readerModelLocator.blogSource), ReaderModelLocator.MAX_SUMMARY_ITEMS);
			sendNotification(ApplicationFacade.BLOG_SUMMARY_CREATE, summary);
		}
		
		/**  
		 * update blog source.
		*/
		public function updateBlogSource(blogSource:BlogSourceVO):void
		{
			if(blogSourceDAO.updateBlogSource(blogSource))
			{
				sendNotification(ApplicationFacade.LABEL_TREE_CREATE, creatLabelTree());
			}
		}
		
		/**  
		 * update list of blog source label.
		*/
		public function updateBlogSourceLabel(blogSource:Vector.<BlogSourceVO>, labelid:int):void
		{
			blogSourceDAO.updateBlogSourcesLabel(Vector.<BlogSourceVO>, labelid);
			getLabels();
		}
		
		/**  
		 * add a new subscribe.
		*/
		public function addSubscribe(blogSource:BlogSourceVO, isQuickAdd:Boolean = false):void
		{			
			var blogsourceid:int = blogSourceDAO.insertBlogSource(blogSource, readerModelLocator.user);
			blogSource.blogSourceId = blogsourceid;
			
			var feedLoader:FeedLoader = new FeedLoader(blogSource);
			feedLoader.addEventListener(FeedLoaderEvent.FEED_INIT, onFeedLoadInit_handler);
			feedLoader.addEventListener(FeedLoaderEvent.FEED_FAIL, onFeedLoodError_handler);
			feedLoader.loadFeed(true);
			
			//if isQuickAdd is true, we will add a deleted subscribe again.
			quickAddSubscribe = isQuickAdd ? blogSource : null;
		}
		
		public function addListSubscribe(list:Vector.<BlogSourceVO>, label:BlogLabelVO):void
		{
			if(label && StringUtils.trimAll(label.name))
			{
				var bs:BlogSourceVO;
				if(label.labelid <= 0)
				{
					var lid:int = labelDAO.insertLabel(label, readerModelLocator.user);
					if(lid > 0)
					{
						for each(bs in list)
						{
							bs.labelId = lid;
						}
					}
				}
				else
				{
					for each(bs in list)
					{
						bs.labelId = label.labelid;
					}
				}
				
			}
			blogSourceDAO.insertBlogsourceList(list, readerModelLocator.user);
			getLabels();
		}
		
		/**  
		 * remove subscribe.
		*/
		public function removeSubscribe(blogSource:BlogSourceVO):void
		{
			if(blogSourceDAO.deleteBlogSource(blogSource) && blogDAO.deleteBlogByBlogSource(blogSource.blogSourceId))
			{
				BlogSourceVO.removeBlogSourceById(blogSource.blogSourceId, readerModelLocator.blogSource);				
				sendNotification(ApplicationFacade.CREATE_LABEL_TREE);
			}
			
		}
		
		/**  
		 * remove subscribes.
		*/
		public function removeSubscribes(blogSources:Vector.<BlogSourceVO>):void
		{
			blogSourceDAO.deleteBlogSources(blogSources);
			blogDAO.deleteBlogByBlogSources(blogSources);
			getLabels();
		}
		
		/**  
		 * search blogs by given keywords.
		*/
		public function searchBlog(keywords:String, blogfetch:BlogFetchVO):void
		{
			var blogSourceIdArray:Vector.<int> = new Vector.<int>();
			if(!blogfetch.blogSourceIds || blogfetch.blogSourceIds.length == 0)
			{
				blogSourceIdArray[0] = blogfetch.blogsource.blogSourceId;
			}
			else
			{
				blogSourceIdArray = blogfetch.blogSourceIds;
			}
			var blogs:Vector.<BlogItemVO> = blogDAO.searchBlog(keywords, readerModelLocator.user, blogSourceIdArray);
			blogfetch.blogItems = blogs;
			sendNotification(ApplicationFacade.BLOG_SEARCH_RESULT, blogfetch);
		}
		
		/**  
		 * fetch blogs.
		*/
		public function fetchBlogs(blogfetch:BlogFetchVO):void
		{
			var blogs:Vector.<BlogItemVO>;
			if(blogfetch.blogSourceIds && blogfetch.blogSourceIds.length > 0)
			{
				//blog list box is in label display state, blogfetch's blogsource is not a real blog-source-vo.
				//select blogitem by user's setting.
				if(readerModelLocator.user.isReadNew)
				{
					blogs = blogDAO.selectByBlogSourceLabelUnread(blogfetch.blogSourceIds);
				}
				else
				{
					blogs = blogDAO.selectByBlogSourceLabel(blogfetch.blogSourceIds);
				}
			}
			else
			{
				//blogfetch's blogsource is a real blog-source-vo.
				if(readerModelLocator.user.isReadNew)
				{
					blogs = blogDAO.selectBlogsByBlogSourceUnread(blogfetch.blogsource.blogSourceId);
				}
				else
				{
					blogs = blogDAO.selectBlogsByBlogSource(blogfetch.blogsource.blogSourceId);
				}
			}
			
			if(blogs && blogs.length > 0 && blogs[0])
			{
				sendNotification(ApplicationFacade.BLOG_FETCH_COMPLETE, blogs);
			}
			else
			{
				sendNotification(ApplicationFacade.BLOG_FETCH_NULL);
			}
			
		}
		
		/**  
		 * update blog item.
		*/
		public function readItem(value:BlogItemVO):void
		{
			blogDAO.updateBlogIsRead(value);
		}
		/**  
		 * update blog items.
		*/
		public function readAllItems(value:Vector.<BlogItemVO>):void
		{
			blogDAO.updateBlogs(value, readerModelLocator.user);
		}
		
		/**  
		 * update blog item, set isStar, isKeepUnRead, etc.
		*/
		public function updateBlogItem(value:BlogItemVO):void
		{
			blogDAO.updateBlog(value);
		}
		
		/**  
		 * fetch all subscribes that stared.
		*/
		public function getStarItems():void
		{			
			var blogs:Vector.<BlogItemVO> = blogDAO.selectBlogsStar(readerModelLocator.user);
			if(blogs && blogs.length > 0)
			{
				sendNotification(ApplicationFacade.BLOG_FETCH_COMPLETE, blogs);
				sendNotification(ApplicationFacade.BLOG_FETCH_ALL, blogs.length);
			}
			else
			{
				sendNotification(ApplicationFacade.BLOG_FETCH_NULL);
			}			
		}
		
		/**  
		 * fetch all subscribes.
		*/
		public function getAllItems():void
		{
			var blogs:Vector.<BlogItemVO> = blogDAO.selectAllBlogsUnread(readerModelLocator.user);
			if(blogs && blogs.length > 0)
			{
				sendNotification(ApplicationFacade.BLOG_FETCH_COMPLETE, blogs);
				sendNotification(ApplicationFacade.BLOG_FETCH_ALL, blogs.length);
			}
			else
			{
				sendNotification(ApplicationFacade.BLOG_FETCH_NULL);
			}			
		}
		
		/**  
		 * get total number of items.
		*/
		public function getCount():void
		{
			var count:CountVO = new CountVO();
			count.totalSubscribes = blogDAO.getCount(readerModelLocator.user);
			count.unreadSubscribes = blogDAO.getUnreadCount(readerModelLocator.user);
			count.totalFeeds = blogSourceDAO.getCount(readerModelLocator.user);
			count.totalLabels = labelDAO.getCount(readerModelLocator.user);
			
			sendNotification(ApplicationFacade.COUNT_DATA, count);
		}
		
		/**  
		 * delete given user.
		*/
		public function deleteAccount():void
		{
			var user:UserVO = readerModelLocator.user;
			blogDAO.deleteBlogByUser(user);
			blogSourceDAO.deleteBlogSourceByUser(user);
			labelDAO.deleteLabelByUser(user);
		}
		
		////////////////////////////////////////////////////////////////////////////////
		//events
		
		/**
		 * after insert a new blogsource, we need to load it's feed and update blogsource and blog tables.
		 */
		private function onFeedLoadInit_handler(e:FeedLoaderEvent):void
		{
			//update blogsource.
			var bs:BlogSourceVO = e.blogSource;
			bs.newBlogs = e.blogItems.length;
			bs.totalBlogs = e.blogItems.length;
			bs.lastPubDate = e.blogItems[0].pubDate;
			
			if(blogSourceDAO.updateBlogSource(bs))
			{
				getLabels();
				
				//insert blog items.
				blogDAO.insertBlogs(e.blogItems, readerModelLocator.user);
			}
			if(quickAddSubscribe)
			{	
				quickAddSubscribe = bs;
			}
			else
			{
				//
			}
			var bf:BlogFetchVO = new BlogFetchVO(bs, null);				
			sendNotification(ApplicationFacade.BLOG_FETCH, bf);
			
			//remove feedLoader event listener.
			var feedLoader:FeedLoader = e.target as FeedLoader;
			feedLoader.removeEventListener(FeedLoaderEvent.FEED_INIT, onFeedLoadInit_handler);
			feedLoader.removeEventListener(FeedLoaderEvent.FEED_FAIL, onFeedLoodError_handler);
		}
		
		private function onFeedLoodError_handler(e:FeedLoaderEvent):void
		{
			var feedLoader:FeedLoader = e.target as FeedLoader;
			feedLoader.removeEventListener(FeedLoaderEvent.FEED_INIT, onFeedLoadInit_handler);
			feedLoader.removeEventListener(FeedLoaderEvent.FEED_FAIL, onFeedLoodError_handler);
			getLabels();
			var bf:BlogFetchVO = new BlogFetchVO(e.blogSource, null);				
			sendNotification(ApplicationFacade.BLOG_FETCH, bf);
		}
		
		private function onFeedLoadListComplete_handler(e:FeedLoaderEvent):void
		{
			blogDAO.insertBlogs(e.blogItems, readerModelLocator.user)
			blogSourceDAO.updateBlogSourceList(readerModelLocator.blogSource);
			sendNotification(ApplicationFacade.LABEL_TREE_CREATE, creatLabelTree());
		}
	}
}